์๋ฐ์คํฌ๋ฆฝํธ์ ๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ํตํด ํจ์จ์ ์ด๊ณ ์์ ์ ์ธ ๋ฆฌ์์ค ์ฒ๋ฆฌ๋ฅผ ๊ฒฝํํ์ธ์. 'using' ๋ฐ 'await using' ๊ตฌ๋ฌธ์ผ๋ก ์ฝ๋์ ์ ์ด๋ ฅ๊ณผ ์์ธก ๊ฐ๋ฅ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ: `using` ๋ฐ `await using` ๋ง์คํฐํ๊ธฐ
๋์์์ด ๋ฐ์ ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ ํ๊ฒฝ์์ ๋ฆฌ์์ค๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ํ์ผ ํธ๋ค, ๋คํธ์ํฌ ์ฐ๊ฒฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
๋ฑ ์ธ๋ถ ๋ฆฌ์์ค๋ฅผ ๋ค๋ฃฐ ๋ ์ ์ ํ ์ ๋ฆฌ๋ ๋ฉ๋ชจ๋ฆฌ ๋์, ๋ฆฌ์์ค ๊ณ ๊ฐ, ์๊ธฐ์น ์์ ์ ํ๋ฆฌ์ผ์ด์
๋์์ ๋ฐฉ์งํ๋ ๋ฐ ํ์์ ์
๋๋ค. ์ญ์ฌ์ ์ผ๋ก ๊ฐ๋ฐ์๋ค์ ์ด๋ฅผ ์ํด try...finally ๋ธ๋ก๊ณผ ๊ฐ์ ํจํด์ ์์กดํด ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค๋ฅธ ์ธ์ด์ ๊ฐ๋
์์ ์๊ฐ์ ๋ฐ์ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ using ๋ฐ await using ๊ตฌ๋ฌธ์ ํตํด ๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ๋์
ํฉ๋๋ค. ์ด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ํ๊ธฐ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ฅผ ์ฒ๋ฆฌํ๋ ๋ ์ ์ธ์ ์ด๊ณ ๊ฒฌ๊ณ ํ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ ์ฝ๋๋ฅผ ๋ ๊นจ๋ํ๊ณ ์์ ํ๋ฉฐ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ํ์์ฑ
using ๋ฐ await using์ ์ธ๋ถ ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ ๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ๊ฐ ์ค์ํ์ง ์ดํดํด ๋ด
์๋ค. ๋ง์ ํ๋ก๊ทธ๋๋ฐ ํ๊ฒฝ์์ ๋ฆฌ์์ค๋ฅผ ํ๋ํ๋ฉด ์ด๋ฅผ ํด์ ํ ์ฑ
์๋ ๋ฐ๋ฆ
๋๋ค. ์ด๋ฅผ ์ ๋๋ก ์ํํ์ง ์์ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค:
- ๋ฆฌ์์ค ๋์: ํด์ ๋์ง ์์ ๋ฆฌ์์ค๋ ๋ฉ๋ชจ๋ฆฌ๋ ์์คํ ํธ๋ค์ ์๋นํ๋ฉฐ, ์ด๋ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ์ถ์ ๋์ด ์ฑ๋ฅ์ ์ ํ์ํค๊ฑฐ๋ ์์คํ ๋ถ์์ ์ ์ ๋ฐํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ ์์: ๋ถ์์ ํ ํธ๋์ญ์ ์ด๋ ๋ถ์ ์ ํ๊ฒ ๋ซํ ์ฐ๊ฒฐ์ ๋ฐ์ดํฐ์ ๋ถ์ผ์น๋ ์์์ ์ด๋ํ ์ ์์ต๋๋ค.
- ๋ณด์ ์ทจ์ฝ์ : ์ด๋ ค ์๋ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด๋ ํ์ผ ํธ๋ค์ ์ผ๋ถ ์๋๋ฆฌ์ค์์ ์ ๋๋ก ๊ด๋ฆฌ๋์ง ์์ ๊ฒฝ์ฐ ๋ณด์ ์ํ์ ์ด๋ํ ์ ์์ต๋๋ค.
- ์๊ธฐ์น ์์ ๋์: ๊ธฐ์กด ๋ฆฌ์์ค๊ฐ ํด์ ๋์ง ์์ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ํ๋ํ ์ ์๋ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋น์ ์์ ์ผ๋ก ๋์ํ ์ ์์ต๋๋ค.
์ ํต์ ์ผ๋ก ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๋ค์ try...finally ๋ธ๋ก๊ณผ ๊ฐ์ ํจํด์ ์ฌ์ฉํ์ฌ try ๋ธ๋ก ๋ด์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์ ๋ฆฌ ๋ก์ง์ด ์คํ๋๋๋ก ๋ณด์ฅํ์ต๋๋ค. ํ์ผ์ ์ฝ๋ ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค๋ฅผ ๊ณ ๋ คํด ๋ด
์๋ค:
function readFileContent(filePath) {
let fileHandle = null;
try {
fileHandle = openFile(filePath); // Assume openFile returns a resource handle
const content = readFromFile(fileHandle);
return content;
} finally {
if (fileHandle && typeof fileHandle.close === 'function') {
fileHandle.close(); // Ensure the file is closed
}
}
}
์ด ํจํด์ ํจ๊ณผ์ ์ด์ง๋ง, ์ฌ๋ฌ ๋ฆฌ์์ค๋ ์ค์ฒฉ๋ ์์ ์ ๋ค๋ฃฐ ๋ ์ฅํฉํด์ง ์ ์์ต๋๋ค. ๋ฆฌ์์ค ์ ๋ฆฌ์ ์๋๊ฐ ์ ์ด ํ๋ฆ ์์ ๋ค์ ๋ฌปํ ์์ต๋๋ค. ๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ ์ ๋ฆฌ ์๋๋ฅผ ๋ช ํํ๊ฒ ํ๊ณ ๋ฆฌ์์ค์ ๋ฒ์์ ์ง์ ์ฐ๊ฒฐํจ์ผ๋ก์จ ์ด๋ฅผ ๋จ์ํํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค์ `Symbol.dispose`
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ๊ธฐ์ด๋ ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค(disposable resources)๋ผ๋ ๊ฐ๋
์ ์์ต๋๋ค. ๋ฆฌ์์ค๋ ์์ ์ ์ ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋ ํน์ ๋ฉ์๋๋ฅผ ๊ตฌํํ ๊ฒฝ์ฐ ํ๊ธฐ ๊ฐ๋ฅ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. ์ด ๋ฉ์๋๋ ์ ์๋ ค์ง ์๋ฐ์คํฌ๋ฆฝํธ ์ฌ๋ณผ์ธ Symbol.dispose๋ก ์๋ณ๋ฉ๋๋ค.
[Symbol.dispose]()๋ผ๋ ์ด๋ฆ์ ๋ฉ์๋๋ฅผ ๊ฐ์ง ๋ชจ๋ ๊ฐ์ฒด๋ ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. using ๋๋ await using ๊ตฌ๋ฌธ์ด ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด๊ฐ ์ ์ธ๋ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๋, ์๋ฐ์คํฌ๋ฆฝํธ๋ ์๋์ผ๋ก ํด๋น ๊ฐ์ฒด์ [Symbol.dispose]() ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๋ ๋ฒ์๊ฐ ์ด๋ป๊ฒ ์ข
๋ฃ๋๋ (์ ์ ์๋ฃ, ์ค๋ฅ, ๋๋ return ๊ตฌ๋ฌธ) ์ ๋ฆฌ ์์
์ด ์์ธก ๊ฐ๋ฅํ๊ณ ์์ ์ ์ผ๋ก ์ํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
์ง์ ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด ๋ง๋ค๊ธฐ
[Symbol.dispose]() ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์์ ๋ง์ ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ํ์ผ์ ์ด๊ณ ๋ซ๋ ๊ฒ์ ์๋ฎฌ๋ ์ด์
ํ๋ ๊ฐ๋จํ `FileHandler` ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ด
์๋ค:
class FileHandler {
constructor(name) {
this.name = name;
console.log(`File \"${this.name}\" opened.`);
this.isOpen = true;
}
read() {
if (!this.isOpen) {
throw new Error(`File \"${this.name}\" is already closed.`);
}
console.log(`Reading from file \"${this.name}\"...`);
// Simulate reading content
return `Content of ${this.name}`;
}
// The crucial cleanup method
[Symbol.dispose]() {
if (this.isOpen) {
console.log(`Closing file \"${this.name}\"...`);
this.isOpen = false;
// Perform actual cleanup here, e.g., close file stream, release handle
}
}
}
// Example usage without 'using' (demonstrating the concept)
function processFileLegacy(filename) {
let handler = null;
try {
handler = new FileHandler(filename);
const data = handler.read();
console.log(`Read data: ${data}`);
return data;
} finally {
if (handler) {
handler[Symbol.dispose]();
}
}
}
// processFileLegacy('example.txt');
์ด ์์ ์์ `FileHandler` ํด๋์ค๋ ๋ฉ์์ง๋ฅผ ๊ธฐ๋กํ๊ณ ๋ด๋ถ ํ๋๊ทธ๋ฅผ ์ค์ ํ๋ [Symbol.dispose]() ๋ฉ์๋๋ฅผ ๊ฐ์ง๋๋ค. ๋ง์ฝ ์ด ํด๋์ค๋ฅผ using ๊ตฌ๋ฌธ๊ณผ ํจ๊ป ์ฌ์ฉํ๋ค๋ฉด, ๋ฒ์๊ฐ ๋๋ ๋ [Symbol.dispose]() ๋ฉ์๋๊ฐ ์๋์ผ๋ก ํธ์ถ๋ ๊ฒ์
๋๋ค.
using ๊ตฌ๋ฌธ: ๋๊ธฐ์ ๋ฆฌ์์ค ๊ด๋ฆฌ
using ๊ตฌ๋ฌธ์ ๋๊ธฐ์ ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ค๊ณ๋์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ ์ธ๋ ๋ธ๋ก์ด๋ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๋ ์๋์ผ๋ก ํ๊ธฐ๋ ๋ณ์๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค. ๊ตฌ๋ฌธ์ ๊ฐ๋จํฉ๋๋ค:
{
using resource = new DisposableResource();
// ... use resource ...
}
// resource[Symbol.dispose]() is automatically called here
์ด์ ์ ํ์ผ ์ฒ๋ฆฌ ์์ ๋ฅผ using์ ์ฌ์ฉํ์ฌ ๋ฆฌํฉํ ๋งํด ๋ด
์๋ค:
function processFileWithUsing(filename) {
try {
using file = new FileHandler(filename);
const data = file.read();
console.log(`Read data: ${data}`);
return data;
} catch (error) {
console.error(`An error occurred: ${error.message}`);
// FileHandler's [Symbol.dispose]() will still be called here
throw error;
}
}
// processFileWithUsing('another_example.txt');
try...finally ๋ธ๋ก์ด ๋ ์ด์ `file`์ ํ๊ธฐ๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด ํ์ํ์ง ์๋ค๋ ์ ์ ์ฃผ๋ชฉํ์ธ์. using ๊ตฌ๋ฌธ์ด ์ด๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋ธ๋ก ๋ด์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ๋ธ๋ก์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋๋ฉด file[Symbol.dispose]()๊ฐ ํธ์ถ๋ฉ๋๋ค.
๋ค์ค `using` ์ ์ธ
์์ฐจ์ ์ธ using ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ๋์ผํ ๋ฒ์ ๋ด์์ ์ฌ๋ฌ ๊ฐ์ ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค๋ฅผ ์ ์ธํ ์ ์์ต๋๋ค:
function processMultipleFiles(file1Name, file2Name) {
using file1 = new FileHandler(file1Name);
using file2 = new FileHandler(file2Name);
console.log(`Processing ${file1.name} and ${file2.name}`);
const data1 = file1.read();
const data2 = file2.read();
console.log(`Read: ${data1}, ${data2}`);
// When this block ends, file2[Symbol.dispose]() will be called first,
// then file1[Symbol.dispose]() will be called.
}
// processMultipleFiles('input.txt', 'output.txt');
๊ธฐ์ตํด์ผ ํ ์ค์ํ ์ธก๋ฉด์ ํ๊ธฐ ์์์
๋๋ค. ๋์ผํ ๋ฒ์ ๋ด์ ์ฌ๋ฌ using ์ ์ธ์ด ์์ ๋, ๊ทธ๋ค์ [Symbol.dispose]() ๋ฉ์๋๋ ์ ์ธ๋ ์์์ ์ญ์์ผ๋ก ํธ์ถ๋ฉ๋๋ค. ์ด๋ ์ค์ฒฉ๋ try...finally ๋ธ๋ก์ด ์์ฐ์ค๋ฝ๊ฒ ํด์ ๋๋ ๋ฐฉ์๊ณผ ์ ์ฌํ ํ์
์ ์ถ(LIFO) ์์น์ ๋ฐ๋ฆ
๋๋ค.
๊ธฐ์กด ๊ฐ์ฒด์ `using` ํจ๊ป ์ฌ์ฉํ๊ธฐ
using์ผ๋ก ์ ์ธ๋์ง ์์์ง๋ง ํ๊ธฐ ๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์๋ ๊ฐ์ฒด๊ฐ ์๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ํด๋น ๊ฐ์ฒด๊ฐ [Symbol.dispose]()๋ฅผ ๊ตฌํํ๋ค๋ฉด, ๊ธฐ์กด ๊ฐ์ฒด์ ํจ๊ป using ์ ์ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ์ข
์ข
ํจ์ ํธ์ถ์์ ์ป์ ๊ฐ์ฒด์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ๋ธ๋ก ๋ด์์ ์ํ๋ฉ๋๋ค:
function createAndProcessFile(filename) {
const handler = getFileHandler(filename); // Assume getFileHandler returns a disposable FileHandler
{
using disposableHandler = handler;
const data = disposableHandler.read();
console.log(`Processed: ${data}`);
}
// disposableHandler[Symbol.dispose]() called here
}
// createAndProcessFile('config.json');
์ด ํจํด์ ํ๊ธฐ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ฅผ ๋ฐํํ์ง๋ง ์ฆ๊ฐ์ ์ธ ํ๊ธฐ๋ฅผ ๊ฐ์ ํ์ง ์๋ API๋ฅผ ๋ค๋ฃฐ ๋ ํนํ ์ ์ฉํฉ๋๋ค.
await using ๊ตฌ๋ฌธ: ๋น๋๊ธฐ์ ๋ฆฌ์์ค ๊ด๋ฆฌ
I/O, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ ๋คํธ์ํฌ ์์ฒญ๊ณผ ๊ด๋ จ๋ ๋ง์ ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์
์ ๋ณธ์ง์ ์ผ๋ก ๋น๋๊ธฐ์ ์
๋๋ค. ์ด๋ฌํ ์๋๋ฆฌ์ค์์๋ ๋ฆฌ์์ค์ ๋น๋๊ธฐ์ ์ ๋ฆฌ ์์
์ด ํ์ํ ์ ์์ต๋๋ค. ๋ฐ๋ก ์ด ๋ถ๋ถ์์ await using ๊ตฌ๋ฌธ์ด ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ ๋น๋๊ธฐ์ ์ผ๋ก ํ๊ธฐ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ค๊ณ๋์์ต๋๋ค.
๋น๋๊ธฐ์ ์ผ๋ก ํ๊ธฐ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ ์ ์๋ ค์ง ์๋ฐ์คํฌ๋ฆฝํธ ์ฌ๋ณผ์ธ Symbol.asyncDispose๋ก ์๋ณ๋๋ ๋น๋๊ธฐ ์ ๋ฆฌ ๋ฉ์๋๋ฅผ ๊ตฌํํ ๊ฐ์ฒด์
๋๋ค.
await using ๊ตฌ๋ฌธ์ด ๋น๋๊ธฐ์ ์ผ๋ก ํ๊ธฐ ๊ฐ๋ฅํ ๊ฐ์ฒด์ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๋, ์๋ฐ์คํฌ๋ฆฝํธ๋ ์๋์ผ๋ก ํด๋น ๊ฐ์ฒด์ [Symbol.asyncDispose]() ๋ฉ์๋ ์คํ์ awaitํฉ๋๋ค. ์ด๋ ์ฐ๊ฒฐ์ ๋ซ๊ธฐ ์ํ ๋คํธ์ํฌ ์์ฒญ, ๋ฒํผ ํ๋ฌ์ ๋๋ ๊ธฐํ ๋น๋๊ธฐ ์ ๋ฆฌ ์์
์ ํฌํจํ ์ ์๋ ์์
์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
๋น๋๊ธฐ์ ์ผ๋ก ํ๊ธฐ ๊ฐ๋ฅํ ๊ฐ์ฒด ๋ง๋ค๊ธฐ
๋น๋๊ธฐ์ ์ผ๋ก ํ๊ธฐ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๋ ค๋ฉด async ํจ์์ฌ์ผ ํ๋ [Symbol.asyncDispose]() ๋ฉ์๋๋ฅผ ๊ตฌํํฉ๋๋ค:
class AsyncFileHandler {
constructor(name) {
this.name = name;
console.log(`Async file \"${this.name}\" opened.`);
this.isOpen = true;
}
async readAsync() {
if (!this.isOpen) {
throw new Error(`Async file \"${this.name}\" is already closed.`);
}
console.log(`Async reading from file \"${this.name}\"...`);
// Simulate asynchronous reading
await new Promise(resolve => setTimeout(resolve, 50));
return `Async content of ${this.name}`;
}
// The crucial asynchronous cleanup method
async [Symbol.asyncDispose]() {
if (this.isOpen) {
console.log(`Async closing file \"${this.name}\"...`);
this.isOpen = false;
// Simulate an asynchronous cleanup operation, e.g., flushing buffers
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Async file \"${this.name}\" fully closed.`);
}
}
}
// Example usage without 'await using'
async function processFileAsyncLegacy(filename) {
let handler = null;
try {
handler = new AsyncFileHandler(filename);
const content = await handler.readAsync();
console.log(`Async read data: ${content}`);
return content;
} finally {
if (handler) {
// Need to await the async dispose if it's async
if (typeof handler[Symbol.asyncDispose] === 'function') {
await handler[Symbol.asyncDispose]();
} else if (typeof handler[Symbol.dispose] === 'function') {
handler[Symbol.dispose]();
}
}
}
}
// processFileAsyncLegacy('async_example.txt');
์ด `AsyncFileHandler` ์์ ์์ ์ ๋ฆฌ ์์
์์ฒด๋ ๋น๋๊ธฐ์ ์
๋๋ค. await using์ ์ฌ์ฉํ๋ฉด ์ด ๋น๋๊ธฐ ์ ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ธฐ๋ค๋ ค์ง๋๋ก ๋ณด์ฅํฉ๋๋ค.
`await using` ์ฌ์ฉํ๊ธฐ
await using ๊ตฌ๋ฌธ์ using๊ณผ ์ ์ฌํ๊ฒ ์๋ํ์ง๋ง ๋น๋๊ธฐ์ ํ๊ธฐ๋ฅผ ์ํด ์ค๊ณ๋์์ต๋๋ค. ์ด๋ async ํจ์ ๋ด์์ ๋๋ ๋ชจ๋์ ์ต์์ ์์ค์์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
async function processFileWithAwaitUsing(filename) {
try {
await using file = new AsyncFileHandler(filename);
const data = await file.readAsync();
console.log(`Async read data: ${data}`);
return data;
} catch (error) {
console.error(`An async error occurred: ${error.message}`);
// AsyncFileHandler's [Symbol.asyncDispose]() will still be awaited here
throw error;
}
}
// Example of calling the async function:
// processFileWithAwaitUsing('another_async_example.txt').catch(console.error);
await using ๋ธ๋ก์ ๋ฒ์ด๋ ๋, ์๋ฐ์คํฌ๋ฆฝํธ๋ ์๋์ผ๋ก file[Symbol.asyncDispose]()๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค. ์ด๋ ์คํ์ด ๋ธ๋ก์ ์ง๋ ๊ณ์๋๊ธฐ ์ ์ ๋ชจ๋ ๋น๋๊ธฐ ์ ๋ฆฌ ์์
์ด ์๋ฃ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ค์ค `await using` ์ ์ธ
using๊ณผ ์ ์ฌํ๊ฒ, ๋์ผํ ๋ฒ์ ๋ด์์ ์ฌ๋ฌ await using ์ ์ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ํ๊ธฐ ์์๋ LIFO(ํ์
์ ์ถ)๋ฅผ ์ ์งํฉ๋๋ค:
async function processMultipleAsyncFiles(file1Name, file2Name) {
await using file1 = new AsyncFileHandler(file1Name);
await using file2 = new AsyncFileHandler(file2Name);
console.log(`Processing async ${file1.name} and ${file2.name}`);
const data1 = await file1.readAsync();
const data2 = await file2.readAsync();
console.log(`Async read: ${data1}, ${data2}`);
// When this block ends, file2[Symbol.asyncDispose]() will be awaited first,
// then file1[Symbol.asyncDispose]() will be awaited.
}
// Example of calling the async function:
// processMultipleAsyncFiles('async_input.txt', 'async_output.txt').catch(console.error);
์ฌ๊ธฐ์ ํต์ฌ์ ๋น๋๊ธฐ ๋ฆฌ์์ค์ ๊ฒฝ์ฐ, await using์ด ๋น๋๊ธฐ ์ ๋ฆฌ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ธฐ๋ค๋ ค์ง๋๋ก ๋ณด์ฅํ์ฌ ์ ์ฌ์ ์ธ ๊ฒฝ์ ์กฐ๊ฑด์ด๋ ๋ถ์์ ํ ๋ฆฌ์์ค ํ ๋น ํด์ ๋ฅผ ๋ฐฉ์งํ๋ค๋ ๊ฒ์
๋๋ค.
๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ๋ฆฌ์์ค ํผํฉ ์ฒ๋ฆฌ
๋์ผํ ๋ฒ์ ๋ด์์ ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค๋ฅผ ๋ชจ๋ ๊ด๋ฆฌํด์ผ ํ ๋ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์? ์๋ฐ์คํฌ๋ฆฝํธ๋ using ๋ฐ await using ์ ์ธ์ ํผํฉํ์ฌ ์ฌ์ฉํ ์ ์๋๋ก ํ์ฌ ์ด ๋ฌธ์ ๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํฉ๋๋ค.
๊ฐ๋จํ ๊ตฌ์ฑ ๊ฐ์ฒด์ ๊ฐ์ ๋๊ธฐ ๋ฆฌ์์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ๊ณผ ๊ฐ์ ๋น๋๊ธฐ ๋ฆฌ์์ค๊ฐ ์๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ด ์๋ค:
class SyncConfig {
constructor(name) {
this.name = name;
console.log(`Sync config \"${this.name}\" loaded.`);
}
getSetting(key) {
console.log(`Getting setting from ${this.name}`);
return `value_for_${key}`;
}
[Symbol.dispose]() {
console.log(`Disposing sync config \"${this.name}\"...`);
}
}
class AsyncDatabaseConnection {
constructor(connectionString) {
this.connectionString = connectionString;
console.log(`Async DB connection to \"${this.connectionString}\" opened.`);
this.isConnected = true;
}
async queryAsync(sql) {
if (!this.isConnected) {
throw new Error('Database connection is closed.');
}
console.log(`Executing query: ${sql}`);
await new Promise(resolve => setTimeout(resolve, 70));
return [{ id: 1, name: 'Sample Data' }];
}
async [Symbol.asyncDispose]() {
if (this.isConnected) {
console.log(`Closing async DB connection to \"${this.connectionString}\"...`);
this.isConnected = false;
await new Promise(resolve => setTimeout(resolve, 120));
console.log('Async DB connection closed.');
}
}
}
async function manageMixedResources(configName, dbConnectionString) {
try {
using config = new SyncConfig(configName);
await using dbConnection = new AsyncDatabaseConnection(dbConnectionString);
const setting = config.getSetting('timeout');
console.log(`Retrieved setting: ${setting}`);
const results = await dbConnection.queryAsync('SELECT * FROM users');
console.log('Query results:', results);
// Order of disposal:
// 1. dbConnection[Symbol.asyncDispose]() will be awaited.
// 2. config[Symbol.dispose]() will be called.
} catch (error) {
console.error(`Error in mixed resource management: ${error.message}`);
throw error;
}
}
// Example of calling the async function:
// manageMixedResources('app_settings', 'postgresql://user:pass@host:port/db').catch(console.error);
์ด ์๋๋ฆฌ์ค์์ ๋ธ๋ก์ ๋ฒ์ด๋ ๋:
- ๋น๋๊ธฐ ๋ฆฌ์์ค(
dbConnection)์[Symbol.asyncDispose]()๊ฐ ๋จผ์ ๊ธฐ๋ค๋ ค์ง๋๋ค. - ๊ทธ ๋ค์, ๋๊ธฐ ๋ฆฌ์์ค(
config)์[Symbol.dispose]()๊ฐ ํธ์ถ๋ฉ๋๋ค.
์ด ์์ธก ๊ฐ๋ฅํ ํด์ ์์๋ ๋น๋๊ธฐ ์ ๋ฆฌ๊ฐ ์ฐ์ ์๋๊ณ ๋๊ธฐ ์ ๋ฆฌ๊ฐ ๋ค๋ฐ๋ฅด๋๋ก ๋ณด์ฅํ์ฌ, ๋ ์ข ๋ฅ์ ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค์ ๊ฑธ์ณ LIFO ์์น์ ์ ์งํฉ๋๋ค.
๋ช ์์ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ์ด์
using ๋ฐ await using์ ์ฑํํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์์๊ฒ ๋ค์๊ณผ ๊ฐ์ ๋ช ๊ฐ์ง ๊ฐ๋ ฅํ ์ด์ ์ ์ ๊ณตํฉ๋๋ค:
- ๊ฐ๋
์ฑ ๋ฐ ๋ช
ํ์ฑ ํฅ์: ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํ๊ณ ํ๊ธฐํ๋ ค๋ ์๋๊ฐ ๋ช
์์ ์ด๊ณ ์ง์ญํ๋์ด ์ฝ๋๋ฅผ ์ดํดํ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๋๋ค. ์ ์ธ์ ํน์ฑ์ ์๋
try...finally๋ธ๋ก์ ๋นํด ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ค์ฌ์ค๋๋ค. - ์ ๋ขฐ์ฑ ๋ฐ ๊ฒฌ๊ณ ์ฑ ํฅ์: ์ค๋ฅ, ์กํ์ง ์์ ์์ธ ๋๋ ์กฐ๊ธฐ ๋ฐํ์ด ์๋ ๊ฒฝ์ฐ์๋ ์ ๋ฆฌ ๋ก์ง์ด ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ๋ฆฌ์์ค ๋์ ์ํ์ ํฌ๊ฒ ์ค์ ๋๋ค.
- ๋จ์ํ๋ ๋น๋๊ธฐ ์ ๋ฆฌ:
await using์ ๋น๋๊ธฐ ์ ๋ฆฌ ์์ ์ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํ์ฌ, ๋ง์ ํ๋ I/O ๊ธฐ๋ฐ ์์ ์ ์ค์ํ ์ ์ ํ ๋๊ธฐ ๋ฐ ์๋ฃ๋ฅผ ๋ณด์ฅํฉ๋๋ค. - ์์ฉ๊ตฌ ์ฝ๋ ๊ฐ์: ๋ฐ๋ณต์ ์ธ
try...finally๊ตฌ์กฐ๊ฐ ํ์ ์์ด์ ธ ๋ ๊ฐ๊ฒฐํ๊ณ ์ค๋ฅ ๋ฐ์ ๊ฐ๋ฅ์ฑ์ด ์ ์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. - ๋ ๋์ ์ค๋ฅ ์ฒ๋ฆฌ:
using๋๋await using๋ธ๋ก ๋ด์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ํ๊ธฐ ๋ก์ง์ ์ฌ์ ํ ์คํ๋ฉ๋๋ค. ํ๊ธฐ ์ค์ ๋ฐ์ํ๋ ์ค๋ฅ๋ ์ฒ๋ฆฌ๋ฉ๋๋ค. ํ๊ธฐ ์ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด, ํ์ ํ๊ธฐ ์์ ์ด ์๋ฃ๋ ํ ํด๋น ์ค๋ฅ๊ฐ ๋ค์ ๋์ ธ์ง๋๋ค. - ๋ค์ํ ๋ฆฌ์์ค ์ ํ ์ง์: ์ ์ ํ ํ๊ธฐ ์ฌ๋ณผ์ ๊ตฌํํ๋ ๋ชจ๋ ๊ฐ์ฒด์ ์ ์ฉํ ์ ์์ด ํ์ผ, ๋คํธ์ํฌ ์์ผ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ, ํ์ด๋จธ, ์คํธ๋ฆผ ๋ฑ์ ๊ด๋ฆฌํ๋ ๋ฐ ๋ค์ฌ๋ค๋ฅํ ํจํด์ด ๋ฉ๋๋ค.
์ค์ฉ์ ๊ณ ๋ ค์ฌํญ ๋ฐ ๊ธ๋ก๋ฒ ๋ชจ๋ฒ ์ฌ๋ก
using ๋ฐ await using์ ๊ฐ๋ ฅํ ์ถ๊ฐ ๊ธฐ๋ฅ์ด์ง๋ง, ํจ๊ณผ์ ์ธ ๊ตฌํ์ ์ํด ๋ค์ ์ฌํญ์ ๊ณ ๋ คํ์ธ์:
- ๋ธ๋ผ์ฐ์ ๋ฐ Node.js ์ง์: ์ด ๊ธฐ๋ฅ๋ค์ ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ค์ ์ผ๋ถ์ ๋๋ค. ๋์ ํ๊ฒฝ(๋ธ๋ผ์ฐ์ , Node.js ๋ฒ์ )์ด ์ด๋ฅผ ์ง์ํ๋์ง ํ์ธํ์ธ์. ์ค๋๋ ํ๊ฒฝ์ ๊ฒฝ์ฐ Babel๊ณผ ๊ฐ์ ํธ๋์คํ์ผ๋ง ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธํ์ฑ: ๋ฆฌ์์ค๋ฅผ ๋ค๋ฃจ๋ ๋ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ผ์ด๋ฒ, ํ์ผ ์์คํ ๋ชจ๋)๊ฐ ์ด๋ฌํ ์๋ก์ด ๊ตฌ๋ฌธ๊ณผ ํธํ๋๋ ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด๋ ํจํด์ ๋ ธ์ถํ๋๋ก ์ ๋ฐ์ดํธ๋๊ณ ์์ต๋๋ค. ์ฌ์ฉํ๋ ์์กด์ฑ์ ๋ฌธ์๋ฅผ ํ์ธํ์ธ์.
- ํ๊ธฐ ์ค ์ค๋ฅ ์ฒ๋ฆฌ:
[Symbol.dispose]()๋๋[Symbol.asyncDispose]()๋ฉ์๋๊ฐ ์ค๋ฅ๋ฅผ ๋์ง๋ฉด, ์๋ฐ์คํฌ๋ฆฝํธ๋ ํด๋น ์ค๋ฅ๋ฅผ ์ก๊ณ ๋์ผํ ๋ฒ์์ ์ ์ธ๋ ๋ค๋ฅธ ๋ฆฌ์์ค๋ค์ (์ญ์์ผ๋ก) ๊ณ์ ํ๊ธฐํ ๋ค์, ์๋์ ํ๊ธฐ ์ค๋ฅ๋ฅผ ๋ค์ ๋์ง๋๋ค. ์ด๋ ํ์ ํ๊ธฐ๋ฅผ ๋์น์ง ์์ผ๋ฉด์๋ ์ด๊ธฐ ํ๊ธฐ ์คํจ๋ฅผ ์ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค. - ์ฑ๋ฅ: ์ค๋ฒํค๋๋ ๋ฏธ๋ฏธํ์ง๋ง, ์ฑ๋ฅ์ด ์ค์ํ ๋ฃจํ์์ ์๋ช ์ด ์งง์ ํ๊ธฐ ๊ฐ๋ฅ ๊ฐ์ฒด๋ฅผ ๋ง์ด ์์ฑํ ๊ฒฝ์ฐ ์ ์คํ๊ฒ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค. ๋ณด์ฅ๋ ์ ๋ฆฌ์ ์ด์ ์ ์ผ๋ฐ์ ์ผ๋ก ์ฝ๊ฐ์ ์ฑ๋ฅ ๋น์ฉ์ ์์ํฉ๋๋ค.
- ๋ช ํํ ์ด๋ฆ ์ง์ : ํ๊ธฐ ๊ฐ๋ฅ ๋ฆฌ์์ค์ ์ค๋ช ์ ์ธ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ์ฝ๋์์ ๊ทธ ๋ชฉ์ ์ ๋ช ํํ ํ์ธ์.
- ๊ธ๋ก๋ฒ ์ฌ์ฉ์ ์ ์์ฑ: ๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ ํ๋ฆฌ์ผ์ด์
, ํนํ ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋๊ฑฐ๋ ๋ค์ํ ๋คํธ์ํฌ ์กฐ๊ฑด์ ์ํฅ์ ๋ฐ์ ์ ์๋ I/O ๋๋ ๋คํธ์ํฌ ๋ฆฌ์์ค๋ฅผ ๋ค๋ฃจ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ๋, ๊ฒฌ๊ณ ํ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ ๋์ฑ ์ค์ํด์ง๋๋ค.
await using๊ณผ ๊ฐ์ ํจํด์ ๋ค์ํ ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ ๋ฐ ์ ์ฌ์ ์ธ ์ฐ๊ฒฐ ์ค๋จ์ ๊ฑธ์ณ ์์ ์ ์ธ ์์ ์ ๋ณด์ฅํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ํด๋ผ์ฐ๋ ์๋น์ค๋ ๋ถ์ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ ๋, ์ฌ์ฉ์์ ์์น๋ ๋คํธ์ํฌ ํ๊ฒฝ์ ๊ด๊ณ์์ด ์ ์ ํ ๋น๋๊ธฐ์ ์ข ๋ฃ๋ฅผ ๋ณด์ฅํ๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฑ๊ณผ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
๊ฒฐ๋ก
using ๋ฐ await using ๊ตฌ๋ฌธ์ ๋์
์ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ์์ด ์ค์ํ ์ง์ ์ ์๋ฏธํฉ๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ฑํํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ค์ ํนํ ๋ณต์กํ ๋น๋๊ธฐ ์๋๋ฆฌ์ค์์ ๋ฆฌ์์ค ๋์๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋ฐฉ์งํ๊ณ ์์ธก ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์
๋์์ ๋ณด์ฅํ๋ฉฐ, ๋ ๊ฒฌ๊ณ ํ๊ณ ๊ฐ๋
์ฑ ๋์ผ๋ฉฐ ์ ์ง ๊ด๋ฆฌํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด๋ฌํ ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ตฌ๋ฌธ์ ํ๋ก์ ํธ์ ํตํฉํ๋ฉด ๋ฆฌ์์ค๋ฅผ ์์ ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ ๋ช
ํํ ๊ธธ์ ์ฐพ๊ฒ ๋ ๊ฒ์ด๋ฉฐ, ๊ถ๊ทน์ ์ผ๋ก ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํ ๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์
์ผ๋ก ์ด์ด์ง ๊ฒ์
๋๋ค.
๋ช
์์ ๋ฆฌ์์ค ๊ด๋ฆฌ๋ฅผ ๋ง์คํฐํ๋ ๊ฒ์ ์ ๋ฌธ๊ฐ ์์ค์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ ๋ฐ ์์ด ํต์ฌ์ ์ธ ๋จ๊ณ์
๋๋ค. ์ค๋๋ถํฐ ์ํฌํ๋ก์ฐ์ using ๋ฐ await using์ ํตํฉํ์ฌ ๋ ๊นจ๋ํ๊ณ ์์ ํ ์ฝ๋์ ์ด์ ์ ๊ฒฝํํด ๋ณด์ธ์.